Java程序员面试宝典(一)

1. JRE与JDK的区别

1) JRE(Java runtime environment):是Java程序的运行环境,与开发无关。既然要运行,必然有JVM(Java virtual machine,Java虚拟机),还包括所有Java类库的class文件,都在lib目录下,被打包成了jar文件。
2)JDK(Java development kit):是Java的开发工具包,JDK包含了JRE,同时还包含了javac(将源代码编译为字节码.class文件),还包含了很多java程序调试和分析的工具:jconsole,jvisualvm等工具软件,还包含了java程序编写所需的文档和demo例子程序。
如果只需要运行java程序,只需安装JRE就可以了。如果需要编写java程序,需要安装JDK。

2. 配置环境变量

我只安装了JDK(JDK包含了JRE)。
用户变量:编辑Path:在最前面粘贴类库文件路径
D:\Software\Java\jdk1.8.0_31\bin;
系统变量:新建JAVA_HOME:jdk文件路径
D:\Software\Java\jdk1.8.0_31
新建CLASSPATH:类库文件路径,注意前面的点跟分号
.; D:\Software\Java\jdk1.8.0_31\lib
验证开发环境是否搭建成功:
打开cmd,输入javac回车没问题,输入java,回车也没问题。(javac命令用来将源文件编译成字节码,java命令运行Java程序。)

3. Path、JAVA_HOME、CLASSPATH的意义

1)Path:将exe应用程序存在的目录写入Path环境变量中,就可以在任意目录下运行该exe应用程序;
2)JAVA_HOME:就是指定了jdk所在的文件路径。
3)CLASSPATH:指定类库文件的搜索路径。我的配置中有两个路径:点号代表当前目录,另一搜索目录是D:\Software\Java\jdk1.8.0_31\lib。

4. 动态地指定类库的搜索路径:-cp或-classpath

javac –cp D:\Software\Java\jdk1.8.0_31\lib\jconsol.jar HelloWorld.java
java –cp D:\Software\Java\jdk1.8.0_31\lib\jconsol.jar HelloWorld.java

5. jar文件

jar文件是java程序打包后的格式文件,jar主要是方便程序的发布和部署。它一般保存有class文件、配置文件、manifest.mf文件(对jar包及其中的内容做一些设置)。
1)利用IDE工具打包:右击项目-export-runnable JAR file, launch configuration选择入口的main方法的那个类,然后选择export destination。双击jar文件就可以运行。
2)利用dos打包jar文件:jar命令,常用的命令参数:-c创建一个jar包,-f指定jar包文件名,-v生成详细报告并输出至标准设备。

6. Java与C++的区别

任何一门高级语言最终都会变成机器码(二进制)后,才能被计算机所识别。而Java程序或C++程序最终都会变成汇编,再运行。
像C、C++这类高级语言,它们的编译器直接将源码编译成计算机识别的机器码;而Java的跨平台特性,使得它多了一个中间步骤:编译器将Java源码编译成字节码,这些字节码可以在JVM中运行,而大多数操作系统都可安装JVM。

7. Java引用与C++指针的区别

本质上,Java和C++都是想通过引用或指针,找到要操作的目标。
区别:
1) 初始值:Java引用的初始值为null;而C++指针是int型,如不初始化指针,那它的值就不固定,这很危险。
2) 计算:引用不可计算,只能被控制;而指针是内存地址,是int型,如++或–,所以经常用指针来代替数组下标。
3) 内存泄漏:Java引用不会产生内存泄漏;而C++容易产生内存泄漏。
4) 作为参数:Java的方法参数只是传值,引用作为参数使用时,函数内是引用参数的copy,所以在函数内交换两个引用是没有意义的,但在函数内改变一个引用参数的属性是有意义的,因为引用参数的copy和原引用参数所引用的是同一对象;而C++指针作为参数给函数用,实际上就是它所指的地址被函数操作。

8. Java的垃圾回收机制

运行时的数据存储区有堆(heap)和栈(stack)。栈中存放的是基本类型变量的值和引用类型变量的地址,这些数据的分配和释放都是系统自动完成的。堆的管理,不同语言的实现不同:C语言通过操作库函数malloc()和free()来实现;C++使用new和delete语句;Java内存数据的释放是由垃圾回收器自动进行的,数组和对象在没有引用变量指向它们时,就会变成垃圾,但仍占用内存,在一个不确定的时间被垃圾回收器回收。相对于C++,可以避免因忘记释放内存而造成的内存溢出错误。

9. Java Web项目的生成、部署和配置

Java Web开发指的是使用Java语言,并按照Java EE规范开发的Web应用程序,这些应用程序可以部署到任何符合该规范的Web容器中运行。

javaweb应用程序目录结构
Java Web应用程序所需的目录结构
web.xml文件定义了Servlet(标签),过滤器(标签),监听器(标签)和一些参数等信息。Web容器通过对该文件的配置控制整个Web应用程序的行为方式。
Servlet是符合一定规范的Java类,它存活在Web容器中,Servlet是服务器端处理HTTP请求的基本组成单元,包括JSP、过滤器在内的许多技术都基于Servlet实现。
Web应用程序也可用jar打包,不过文件后缀为War。

10. EJB(enterprise java bean)项目的生成和部署问题

EJB是Java EE中的一条规范,它广泛应用于大型分布式项目中。

11. 静态变量、实例变量、局部变量

根据生成周期的不同可分为静态变量、实例变量和局部变量。
成员变量(field,字段、属性)包括:静态(类)变量,实例变量;
局部变量包括:方法里的变量;代码块中的变量。
1) 静态变量由static修饰,它的生存周期由类来决定,当类加载时它们就生成并初始化;
2) 实例变量是类中没有static修饰的变量,它的生存周期由对象决定,随着对象的加载生成并初始化,随着对象被垃圾回收器回收而消失;
3) 局部变量是定义在方法中的变量或参数,它随着方法的调用而创建,随着方法的执行完毕而消失。
静态变量通过类名.静态变量访问;实例变量通过实例.实例变量访问。
若要在方法中使用成员变量,可以用this关键字。

12. 基本数据类型(8种)和引用数据类型两种大的数据类型

基本数据类型直接存放数据的值,而引用类型存放的是数据所在的地址。
Java中几乎所有要处理的东西都是对象,操作对象比操作基本类型更方便,而操作基本类型则更高效。由于基本数据类型存储的都是数据量比较小的数据。对数据量比较大的对象进行数据操作时,会影响效率,因此为所有操作对象的类型定义了一种引用类型(存的值是内存地址)的数据。

13. 装箱(把基本数据类型包装成包装类)

1) 使用new语句;
2) 调用包装类的静态方法valueOf()。

1
2
3
4
int a = 1;
Integer b = new Integer(a); //装箱
Integer c = Integer.valueOf(a); //装箱
int d = b.intValue(); //调用包装类的intValue()方法可以拆箱

14. 自动装箱和自动拆箱

从java 5.0开始有一种自动装箱(autoboxing)和自动拆箱(unboxing)功能,就可以不必显示转换,系统会自动按照需求进行数据类型转换。
自动装箱和拆箱是对基本数据类型及其包装类的相互自动转换,这个过程发生在编译阶段。

1
2
Integer i = 10; //自动装箱
int a = I; //自动拆箱

15. Java的main()方法

main()方法是程序的入口方法,它还接受外部参数(即通过命令提示符输入的参数),字符串数组参数args就是用来接受参数的,它是一个数组的形式,长度与输入参数的个数一致。

16. equals()与==的区别

默认情况下,它们的作用都是相同的,即在比较基本类型的时候,比较它们的实际值是否相等;在比较引用类型的时候,比较它们引用的地址是否相等(即 是否引用的同一对象 )。默认Object类下的equals()方法:

1
2
3
public boolean equals(Object obj){
return (this == obj); //这个对象
}

所以通常需要重写(override)equals()方法,使它比较的是实际值是否相等(即我们通常认为的值相等),equals()方法是java.lang.Object的方法,可以被重写(override),也可自定义方法来判断两个对象是否相等。
而String类的equals()方法已经被重写,比较的是两个字符串序列是否完全相同

17. 提供3种循环结构

for适合确定循环次数;while适合单条件循环;do…while适合执行某代码之后再循环。

18. Java只有一个三元运算符

即条件表达式?表达式1:表达式2。条件表达式是一个布尔表达式,只能返回true或false,如果返回true则执行表达式1,返回false则执行表达式2。
三元运算符不是必须的,它可以被if和else语句替代,它最大的作用是减少了代码量。

19. Java中的注释

1)行注释//和块注释/*…*/;
2)文档注释/**…*/:用来生成API文档;
3)Annotation:与其他注释的本质区别是,它会进入到编译层,并对程序结果产生影响,它用来代替XML提供JPA、Spring等框架的配置信息。

20. 类和对象有什么区别

1)类代表了一种抽象集合,它里面的各种属性和方法代表了每个类实例的特定数据和操作。在类中定义属性和方法。JVM对类只加载一次,对它的静态成员也只加载一次。
类的构造器是一种特殊的方法,它不能被程序员显式调用,只能在创建对象时由系统自动调用。
2)对象是某一特定抽象(即类)的实例,它必须属于某一个类,对象都用new关键字或类名来创建。
简而言之,类是抽象,对象是类的实现。

21. 如何使用继承(extends)重写(override)代码

Java的继承是单继承,即子类只能继承一个父类。子类拥有父类除了私有成员以外的所有成员变量和成员方法。若需要对父类方法进行重写(override,即方法覆盖),定义一个名字、参数、返回值完全相同的方法,实现多态。
Java程序中,所有类都继承自java.lang.Object类,它有9个方法:clone()、equals()、finalize()、getClass()、hashCode()、notify()、notifyAll()、toString()、wait(),则所有的Java类都包含这9个方法。

22. 多态

子类继承父类,重写方法。通过将子类对象引用直接赋值给父类对象引用变量,当运行时调用该引用类型的方法时,其方法总是表现出子类的特征。访问属性时,会得到父类属性(编译时类型),但方法调用的是子类方法(运行时类型)。

1
2
3
//同样是人,亚洲人和欧洲人眼睛颜色这个方法不同)
Man asiaMan = new AsiaMan();
Man euroMan = new EuroMan();

asiaMan和euroMan都是Man类型,但他们的实现不同,表现出来的形态也就不同,这就是多态。

23. 重载(overload)

创建一个方法名相同,但参数列表不同的方法。

24. Java中静态成员的特点

静态成员是static修饰的成员,它属于一个类所有,这个类的所有实例可以共享它们。
特点:在类加载时,就进行创建和初始化或执行代码;对一个类来说,都只有一份;类的所有实例都可以访问到它们。
主要包括:
1) 静态变量:被static修饰的成员变量,在类加载时执行创建和初始化。因为它的唯一性,通常用于对象的数据记录,如单例模式下想引用保存。
2) 静态代码块:被static修饰,在类加载时被调用。被{ }括起来的代码,可以使用静态变量和方法。
3) 静态方法:被static修饰,直接通过类名访问,(也可通过对象访问)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class StaticTest{
static int a; //类加载时,系统初始化为1
static void staticTest(){
System.out.print("静态方法");
}
static {
System.out.print("静态代码块");
}
public static void main(String[] args){
System.out.println(a);
StaticTest obj = new StaticTest(); //先执行这句
obj.staticTest();
}
}
1
2
3
4
输出:
静态代码块
a
静态方法

执行上述代码,被动引用类字段:JVM会先加载StaticTest类(主类)到内存,然后创建变量a并执行初始化,再执行静态代码块。静态方法需要显式调用。

25. Java子类如何为父类传递参数

super用于访问父类成员,可以用于调用被子类重写的父类成员方法,也可以用来调用父类的构造器。
所有的类在没有提供其他的构造方法(也叫构造器)的时候,都会使用系统提供的默认的构造方法。若父类和子类都使用默认的构造方法,那么子类可以不必显示的调用super(),系统会隐式地调用父类的默认构造方法;但若父类中有需要传入参数的构造方法,那么子类就必须为父类传入这些参数。
例: 无论子类中定义的无参还是有参的构造方法,都需要为父类的有参构造方法传入参数

1
2
3
4
5
6
7
8
9
10
11
12
13
//父类构造方法
class Base(int a){
this.a = a;
}
//子类
class Child extends Base{
Child(){
super(100);
}
Child(int a){
super(a);
}
}

26. 接口和抽象类的区别

接口和抽象类都包含了一些不完整的信息,都是不能具体地描述一个对象的类型,需要实现类进行具体实现。
1)抽象类(abstract class):包含抽象方法的类。通过abstract class定义。不可以被实例化,抽象类表示一种继承关系,使用extends关键字。一个类只能继承一个父类。
2)接口(interface):所有东西都是抽象的,即所有方法都是抽象的,它也可以包含静态变量,但都是final变量。通过interface定义。不可以被实例化,可以被实现(implements)。一个类可以实现多个接口。

27. 内部类的实质

内部类生存在其它类的内部。内部类的分类:
1) 静态内部类: 在外部类加载的时候,静态内部类也随之加载。其完整类名为包名.外部类.内部类。编译后的class文件后缀为Outer$Inner.class。静态内部类对于外部类来说,仅仅是包含关系,缩小了命名空间, 它们是两个独立的类 ,JVM也不知道它们两个有包含关系。
2) 成员内部类:此时的内部类需要等外部类创建了对象后才被加到JVM中, 先有外部类实例才有内部类实例(因此成员内部类不能有static方法或变量),它属于外部类的某个实例,因此可以访问外部类的任意成员。创建成员内部类的语法:先创建外部类的实例,然后用此实例调用new语句。

1
2
Outer o = new Outer();
Outer.Inner I = o.new Inner();

对于成员内部类的构造方法,系统会为它们自动加上一个外部类的参数和外部类的成员变量。成员内部类的本质构造方法:

1
2
3
Inner(Outer o){
this.o = o;
}

当内部类访问外部成员时,则是通过自动添加的外部类变量进行访问。
3) 局部内部类:只在定义它的方法内部有效。不能使用static关键字,只能使用final和abstract关键字,仅可访问外部类 带final关键字的局部变量,但可以访问 任意外部类对象的成员变量。局部内部类定义在static方法里就相当于静态内部类;定义在普通方法里就相当于成员内部类。
4) 匿名内部类:局部内部类(存在于方法里)没有名字,则它就是一个匿名内部类。匿名内部类的工作原理相当于局部内部类,只是它没有具体名字,也不能被外部类直接使用。匿名内部类编译后的class文件的命名是按匿名内部类的的排列顺序进行的,如Outer$1.class

1
2
3
4
5
public void abc(){
new Inner(){

};
}

28. 包

包可以有效防止重名。当需要把一个类定义在某个包下的时候,使用package关键字。当需要使用其它包下的类的时候,使用import关键字。

29. 4种访问控制符

private、default、protected、public。

访问控制符 具体控制范围
private 当前类访问权限。用于修饰成员变量最合适,将成员变量隐藏在该类的内部。
default 包访问权限。默认即什么访问控制符都不加,被default修饰的成员或外部类只能被相同包下的其它类访问。
protected 子类访问权限。被protected修饰的成员既可以被同一包内的其它类访问,也可以被不同包的子类访问。通常情况下,如果使用protected来修饰一个方法,通常是希望其子类重写这个方法。
public 公共访问权限。可以被所有类访问,不管是不是在同一个包中,不管是否具有父子继承关系。
# 30. int和Integer的区别 #
1)int型
int是8种基础数据类型中的一种,基础数据类型保存在栈内存(虚拟机栈)中。int型数据占4个字节(32位),取值范围:-2^31~2^31-1。第1位是正负符号位(0表示正,1表示负),后面31位表示数值。
2) Integer是int的包装类,在参数传递的时候,传递的是它所代表的对象的一个引用。
注意:所有数字在计算机中都是以二进制存在的,计算机是以补码的形式保存所有的整数。所以原码即是补码除最高位外,其它位取反,减1得到的
反码:最高位(符号位)保持不变,对原码按位取反。
补码:正数的补码与原码完全相同;负数的补码是其反码加1。
八进制以0开头,十六进制以0x开头。它们虽然用得不多,八进制可以用来表示掩码,十六进制用来表示颜色。